package cli

import (
	"gamesdk/common/libnet/inter"
	"gamesdk/common/libnet/io"
	"gamesdk/common/libnet/msg"
	"gamesdk/common/log"
	"gamesdk/common/recover"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
)

const (
	g_HearBeat = 1 //心跳消息
)

/*
*用户缓存
 */
type Client struct {
	writeBuf   chan []byte
	readBuf    chan []byte
	timeout    int
	writeClose chan bool
	readClose  chan bool
	heartClose chan bool
	reciveMsg  inter.ReciveMsg
	exit       bool
	ip         string
	heartbeat  time.Duration //心跳时间
	conn       *websocket.Conn
	waitGroup  sync.WaitGroup
}

func NewClient(conn *websocket.Conn, ip string, heartbeat int) *Client {
	return &Client{
		conn:       conn,
		timeout:    0,
		reciveMsg:  nil,
		readBuf:    make(chan []byte, 1024),
		writeBuf:   make(chan []byte, 1024),
		writeClose: make(chan bool),
		readClose:  make(chan bool),
		heartClose: make(chan bool),
		exit:       false,
		ip:         ip,
		heartbeat:  time.Duration(heartbeat),
	}
}
func (this *Client) startHeart() {
	defer recover_handle.RecoverHandle("startHeart")

	ticker := time.NewTicker(this.heartbeat * time.Second)
	for {
		select {
		case <-ticker.C:
			log.Debug("heart")
			if this.timeout > 3 {
				log.Debug("timeout timeout send")
				frameMsg := &msg.FrameMsg{MainCmd: 0, SubCmd: 1}
				data, err := proto.Marshal(frameMsg)
				if err != nil {
					log.Warn(err.Error())
					break
				}
				this.SendMsgToClinet(data)

			}

			if this.timeout > 5 {
				this.conn.Close()
				log.Debug("timeout close")
			}

			this.timeout++
		case <-this.heartClose:
			log.Debug("heartClose exit")
			ticker.Stop()
			this.waitGroup.Done()
			return
		}
	}

}

/*
*初始化服务
*参数说明:
*@param:reciveMsg   	接受消息回调函数
 */
func (this *Client) Start(reciveMsg inter.ReciveMsg, exit inter.Exit) {
	defer recover_handle.RecoverHandle("Start")
	this.reciveMsg = reciveMsg
	//启动写入进程
	this.waitGroup.Add(1)
	go this.funcWrite()
	this.waitGroup.Add(1)
	go this.funcRead()

	if this.heartbeat > 0 {
		this.waitGroup.Add(1)
		go this.startHeart()
	}

	for {
		select {
		case buf := <-this.readBuf:
			frameMsg := &msg.FrameMsg{}
			err := proto.Unmarshal(buf, frameMsg)
			if err != nil {
				log.Warn(err.Error())
				break
			}
			//表示心跳包
			if frameMsg.MainCmd == 0 && frameMsg.SubCmd == 1 {
				log.Debug("recvice heart data need send")
				frameMsg := &msg.FrameMsg{MainCmd: 0, SubCmd: 2}
				data, err := proto.Marshal(frameMsg)
				if err != nil {
					log.Warn(err.Error())
					break
				}
				this.SendMsgToClinet(data)
				break
			}
			if frameMsg.MainCmd == 0 && frameMsg.SubCmd == 2 {
				log.Debug("recvice heart data not need send")
				break
			}
			if this.reciveMsg != nil {
				//log.Debug("reciveMsg")
				this.reciveMsg(frameMsg.MainCmd, frameMsg.SubCmd, frameMsg.Buff)
			}

		case <-this.readClose:
			//this.waitGroup.Done()
			goto A
		}
	}

A:

	//关闭资源
	this.waitGroup.Wait()
	close(this.heartClose)
	close(this.writeClose)
	close(this.readClose)
	close(this.writeBuf)
	this.exit = true
	log.Debug("用户退出")
	exit()
	return
}

/*
*启动写
 */
func (this *Client) funcRead() {
	defer recover_handle.RecoverHandle("funcRead")
	for {
		message, err := io.WbRead(this.conn)
		if err != nil {
			log.Error(err.Error())
			//关闭读写队列
			break
		}
		//log.Debug("read %s", string(message))
		this.timeout = 0
		this.readBuf <- message
	}
	this.waitGroup.Done()
	if this.heartbeat > 0 {
		this.heartClose <- true
	}
	this.writeClose <- true
	this.readClose <- true
}

/*
*启动写
 */
func (this *Client) funcWrite() {
	defer recover_handle.RecoverHandle("funcWrite")
	if this.heartbeat <= 0 {
		for {
			select {
			case buf := <-this.writeBuf:
				err := io.WbWrite(this.conn, buf)
				if err != nil {
					log.Warn(err.Error())
					this.conn.Close()
				}

				frameMsg := &msg.FrameMsg{}
				err = proto.Unmarshal(buf, frameMsg)
				if err != nil {
					log.Warn(err.Error())
					break
				}
				//log.Debug("write %v", frameMsg)
			case <-this.writeClose:
				this.waitGroup.Done()
				log.Debug("write exit")
				return
			}
		}
	} else {
		for {
			select {
			case buf := <-this.writeBuf:
				err := io.WbWriteByTime(this.conn, buf, time.Now().Add(time.Second*this.heartbeat))
				if err != nil {
					log.Warn(err.Error())
					this.conn.Close()
				}
			case <-this.writeClose:
				this.waitGroup.Done()
				return
			}
		}
	}
}

/*
*发生消息
 */
func (this *Client) SendMsgToClinet(message []byte) {
	defer recover_handle.RecoverHandle("writeMessage")
	//log.Debug("SendMsgToClinet")
	if !this.exit {
		this.writeBuf <- message
		//log.Debug("SendMsgToClinet2 %s", string(message))
	} else {
		log.Debug("SendMsgToClinet exit")
	}
}

func (this *Client) SendMsgToServer(message []byte) {
}

func (this *Client) GetIp() string {
	return this.ip
}

/*
*用户推出
 */
func (this *Client) Exit() {
	this.conn.Close()
}
